package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baidu.aip.ocr.AipOcr;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hankcs.algorithm.AhoCorasickDoubleArrayTrie;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.file.service.FileStorageService;
import com.heima.file.service.impl.MinIOFileStorageService;
import com.heima.model.article.pojo.ArticleDoc;
import com.heima.model.common.constant.CommonConstant;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.dtos.ContentDto;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.wemedia.config.ApiConfigurationProperties;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsVerifyService;
import com.itheima.leadnews.feign.article.ArticleFeign;
import com.itheima.leadnews.rabbitmq.config.RabbitMqConfig;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.*;

@Service
public class WmNewsVerifyServiceImpl implements WmNewsVerifyService {

    @Autowired
    private GreenImageScan greenImageScan;

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private GreenTextScan greenTextScan;

    @Autowired
    private MinIOFileStorageService minIOFileStorageService;

    @Autowired
    private Configuration configuration;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    @Autowired
    private ArticleFeign articleFeign;

    @Autowired
    private WmUserMapper wmUserMapper;

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired
    private ApiConfigurationProperties apiConfigurationProperties;

    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    @Override
    public void autoScan(WmNews wmNews) throws Exception {
        //1.获取文章中文本和图片
        String content = wmNews.getContent();
        List<ContentDto> contentDtos = JSON.parseArray(content, ContentDto.class);
        Set<String> set = new HashSet<>();//图片
        StringBuilder textStr = new StringBuilder();//文本
        for (ContentDto contentDto : contentDtos) {
            //图片
            if (contentDto.getType().equals(ContentDto.IMAGE)) {
                set.add(contentDto.getValue());
            } else {
                //文本
                textStr.append(contentDto.getValue());
            }
        }
        //将封面图片保存到set集合一起审核,set集合去重
        String images = wmNews.getImages();
        //封面可能无图,判断
        if (StringUtils.isNotEmpty(images)) {
            String[] split = images.split(",");
            Collections.addAll(set, split);
        }

        //百度OCR图片文字识别
        StringBuilder stringBuilder = getStringBuilder(set);
        //和文字放在一起审核
        textStr.append(stringBuilder);

        //字典树
        AhoCorasickDoubleArrayTrie<String> acdat = new AhoCorasickDoubleArrayTrie<String>();
        LambdaQueryWrapper<WmSensitive> queryWrapper = new LambdaQueryWrapper<>();
        Map<String, String> map = new HashMap<>();
        List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(queryWrapper);
        for (WmSensitive wmSensitive : wmSensitives) {
            String sensitives = wmSensitive.getSensitives();
            map.put(sensitives, sensitives);
        }
        acdat.build(map);
        List<AhoCorasickDoubleArrayTrie.Hit<String>> hits = acdat.parseText(textStr.toString());
        if (!hits.isEmpty()) {
            wmNews.setStatus(WmNews.Status.FAIL.getCode());
            String s = hits.toString();
            String substring = s.substring(1, s.length() - 1);
            wmNews.setReason("文章中包含违规词: " + substring);
            wmNewsMapper.updateById(wmNews);
            return;
        }

        //调用阿里云内容安全服务审核文本
        if (StringUtils.isNotEmpty(textStr.toString())) {
            Map resultText = greenTextScan.greeTextScan(textStr.toString());
            String suggestion = (String) resultText.get("suggestion");
            if (suggestion.equals("block")) {
                //违规,修改状态为2,返回
                wmNews.setStatus(WmNews.Status.FAIL.getCode());
                wmNews.setReason("文章中包含违规词: " + resultText.get("label"));
                wmNewsMapper.updateById(wmNews);
                return;
            }
        }
        //调用阿里云的内容安全服务审核图片
        List<byte[]> imageList = new ArrayList<>();
        if (!set.isEmpty()) {
            for (String url : set) {
                byte[] bytes = minIOFileStorageService.downLoadFile(url);
                imageList.add(bytes);
            }
            Map<String, String> resultImage = greenImageScan.imageScan(imageList);
            String imageResult = resultImage.get("suggestion");
            if (imageResult.equals("block")) {
                //违规,修改状态为2,返回
                wmNews.setStatus(WmNews.Status.FAIL.getCode());
                wmNews.setReason("图片中包含违规信息: " + resultImage.get("label"));
                wmNewsMapper.updateById(wmNews);
                return;
            } else if (imageResult.equals("review")) {
                //不确定,修改状态为3,人工审核
                wmNews.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
                wmNews.setReason("转人工审核");
                wmNewsMapper.updateById(wmNews);
                return;
            }
        }
        //判断文章是否设置定时发布(发布时间>当前时间)
        if (wmNews.getPublishTime().after(new Date())) {
            //定时发布,修改状态为8
            wmNews.setStatus(WmNews.Status.SUCCESS.getCode());
            wmNews.setReason("文章审核通过,待发布");
            wmNewsMapper.updateById(wmNews);
            //发送延迟消息到MQ死信队列
            long ttl = wmNews.getPublishTime().getTime() - System.currentTimeMillis();
            //withBody()设置消息
            //setExpiration()设置消息过期时间
            Message message = MessageBuilder.withBody(String.valueOf(wmNews.getId()).getBytes()).setExpiration(String.valueOf(ttl)).build();
            //发送消息到默认交换机,指定消息名称
            rabbitTemplate.convertAndSend(RabbitMqConfig.SEND_QUEUE_NAME,message);
        } else {
            publish(wmNews);
        }
    }


    @Override
    public void publish(WmNews wmNews) {
        //即刻发布,将自媒体文章同步到article服务,保存三个表
        //修改状态为9
        wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
        wmNews.setReason("文章审核通过,已发布");

        WmNewsDto wmNewsDto = new WmNewsDto();
        BeanUtils.copyProperties(wmNews, wmNewsDto);
        //作者名称
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        wmNewsDto.setAuthorName(wmUser.getName());
        //频道名称
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        wmNewsDto.setChannelName(wmChannel.getName());
        //远程调用article服务完成文章发布
        ResponseResult responseResult = articleFeign.saveArticle(wmNewsDto);
        //article文章ID
        Long articleId = (Long) responseResult.getData();
        wmNews.setArticleId(articleId);
        wmNewsMapper.updateById(wmNews);
        String fileName = UUID.randomUUID() + ".html";
        File file = new File("E:\\" + fileName);
        try {
            //准备数据模型
            String content = wmNews.getContent();
            List<ContentDto> contentDtos = JSON.parseArray(content, ContentDto.class);
            Map<String, List<ContentDto>> map = new HashMap<>();
            map.put("content", contentDtos);
            //获取模板对象
            Template template = configuration.getTemplate("article.ftl");
            //文件输出流
            FileWriter fileWriter = new FileWriter(file);
            //生成静态化页面,生成到本地磁盘
            template.process(map, fileWriter);
            //上传到minio
            FileInputStream fileInputStream = new FileInputStream(file);
            String url = fileStorageService.uploadHtmlFile("", fileName, fileInputStream);
            //将上传到minio的静态化页面保存到ap_article表
            articleFeign.updateStaticUrl(articleId, url);
            System.out.println(url);
            fileInputStream.close();
            fileWriter.close();

            //发送消息到ES实现数据同步
            ArticleDoc articleDoc = new ArticleDoc();
            articleDoc.setId(wmNews.getArticleId());
            articleDoc.setPublishTime(wmNews.getPublishTime());
            articleDoc.setLayout(wmNews.getType().intValue());
            articleDoc.setImages(wmNews.getImages());
            articleDoc.setStaticUrl(url);
            articleDoc.setAuthorId(wmNews.getUserId().longValue());
            articleDoc.setAuthorName(wmUser.getName());
            articleDoc.setTitle(wmNews.getTitle());
            StringBuilder stringBuilder = new StringBuilder();
            for (ContentDto contentDto : contentDtos) {
                if (contentDto.getType().equals(ContentDto.TEXT)){
                    stringBuilder.append(contentDto.getValue());
                }
            }
            articleDoc.setContent(stringBuilder.toString());
            kafkaTemplate.send(CommonConstant.TOPIC_ARTICLE_SYNC,String.valueOf(articleDoc.getId()),JSON.toJSONString(articleDoc));


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //删除本地文件
            boolean delete = file.delete();
            System.out.println(delete);
        }
    }

    //百度OCR图片文字识别
    private StringBuilder getStringBuilder(Set<String> set) {
        //初始化一个AipOcr
        AipOcr client = new AipOcr(apiConfigurationProperties.getId(),
                apiConfigurationProperties.getKey(),
                apiConfigurationProperties.getSecret());

        StringBuilder stringBuilder = new StringBuilder();
        for (String s : set) {
            byte[] bytes = fileStorageService.downLoadFile(s);
            //调用接口
            JSONObject res = client.basicGeneral(bytes, new HashMap<String, String>());
            JSONArray result = res.getJSONArray("words_result");
            List<Object> objects = result.toList();
            for (Object o : objects) {
                Map<String, String> map = (Map<String, String>) o;
                String words = map.get("words");
                stringBuilder.append(words);
            }
        }
        return stringBuilder;
    }
}
